using System;
using System.Collections.Generic;
using GameFramework.Core;
using GameFramework.Update;
using GameFramework.Utility;

namespace GameFramework.Game
{
    /// <summary>
    /// 玩法接口
    /// </summary>
    public interface IGame : IInitialize, IDisposable, IFixedUpdate
    {
        /// <summary>
        /// 获取/设置 是否暂停
        /// </summary>
        bool Pause { get; set; }
        
        /// <summary>
        /// 是否正在运行
        /// </summary>
        bool IsRunning { get; }
        
        /// <summary>
        /// 开始玩法
        /// </summary>
        void Start();
        
        /// <summary>
        /// 停止玩法
        /// </summary>
        void Stop();
    }

    /// <summary>
    /// 玩法抽象类
    /// </summary>
    public abstract class AGame : IGame
    {
        public bool Pause { get; set; }
        public bool IsRunning { get; private set; }

        private readonly GameRepositoryRegister m_RepositoryRegister = new GameRepositoryRegister();
        private readonly GameSystemRegister m_SystemRegister = new GameSystemRegister();

        public void Initialize()
        {
            OnRegisterRepository(m_RepositoryRegister);
            OnRegisterSystem(m_SystemRegister);

            m_RepositoryRegister.Initialize();
            m_SystemRegister.Initialize();
            
            OnInitialize();
        }

        public void Dispose()
        {
            if (IsRunning)
                Stop();
            
            OnDispose();
            
            m_SystemRegister.Dispose();
            m_RepositoryRegister.Dispose();
        }

        public void OnFixedUpdate(float elapseSeconds, float realElapseSeconds)
        {
            if (!IsRunning)
                return;
            
            if (Pause)
                return;

            m_SystemRegister.OnFixedUpdate(elapseSeconds, realElapseSeconds);
        }

        public void Start()
        {
            if (IsRunning)
                return;
            
            IsRunning = true;
            
            m_SystemRegister.OnGameStart();
            OnStart();
        }

        public void Stop()
        {
            if (!IsRunning)
                return;
            
            IsRunning = false;
            
            OnStop();
            m_SystemRegister.OnGameStop();
        }

        protected abstract void OnRegisterRepository(IGameRepositoryRegister register);
        protected abstract void OnRegisterSystem(IGameSystemRegister register);
        protected abstract void OnInitialize();
        protected abstract void OnDispose();
        protected abstract void OnStart();
        protected abstract void OnStop();

        /// <summary>
        /// 玩法仓库注册器
        /// </summary>
        protected interface IGameRepositoryRegister : IIOCContainer<IGameRepository>
        {
        }

        /// <summary>
        /// 玩法系统注册器
        /// </summary>
        protected interface IGameSystemRegister : IIOCContainer<IGameSystem>
        {
            /// <summary>
            /// 游戏开始
            /// </summary>
            void OnGameStart();
            
            /// <summary>
            /// 游戏停止
            /// </summary>
            void OnGameStop();
        }

        protected sealed class GameRepositoryRegister : AIOCContainer<IGameRepository>, IGameRepositoryRegister
        {
        }

        protected sealed class GameSystemRegister : AIOCContainer<IGameSystem>, IGameSystemRegister, IFixedUpdate
        {
            private readonly List<IFixedUpdate> m_FixedUpdateSystems = new List<IFixedUpdate>();

            protected override void AfterInitialize()
            {
                base.AfterInitialize();
                foreach (var instance in RegisterInstances)
                {
                    // ReSharper disable once SuspiciousTypeConversion.Global
                    if (instance is IFixedUpdate fixedUpdate)
                        m_FixedUpdateSystems.Add(fixedUpdate);
                }
            }

            public void OnGameStart()
            {
                foreach (var system in RegisterInstances)
                {
                    try
                    {
                        system.OnGameStart();
                    }
                    catch (Exception e)
                    {
                        Log.Exception(e);
                    }
                }
            }

            public void OnGameStop()
            {
                foreach (var system in RegisterInstances)
                {
                    try
                    {
                        system.OnGameStop();
                    }
                    catch (Exception e)
                    {
                        Log.Exception(e);
                    }
                }
            }

            public void OnFixedUpdate(float elapseSeconds, float realElapseSeconds)
            {
                foreach (var update in m_FixedUpdateSystems)
                {
                    try
                    {
                        update.OnFixedUpdate(elapseSeconds, realElapseSeconds);
                    }
                    catch (Exception e)
                    {
                        Log.Exception(e);
                    }
                }
            }
        }
    }
}